/*
 * file hijack.c
 *
 * Hth's TCP Hijacker
 *
 * Hth networks
 * Copyright 2009
 * htt://www.unix-junkies.org
 * mail me at : hth at unix-junkies dot org
 *
 *
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the University of California, Berkeley nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "hijack.h"
#include "options.h"
#include "network.h"
#include "common.h"



static bool target_is_vulnerable(hijack_t * hh);
static bool get_client_port(hijack_t * hh);
static bool get_server_snd_next(hijack_t * hh);
static bool get_client_snd_next(hijack_t * hh);
static uint32_t inject_content(hijack_t * hh);


/*
 * user options
 */
extern flowinsertOpt o;



hijack_t * hijack_startup(char *errbuf) {
    hijack_t * hh = NULL;

    /* check user supplied pointer */
    if (errbuf == NULL)
        return NULL;
    /* try to allocate a new handler */
    if ((hh = (hijack_t *)malloc(sizeof(hijack_t))) == NULL) {
        return NULL;
    }
    /* initialization */
    hh->errorBuffer = errbuf;
    if ((hh->pd = network_pcap_open(hh->errorBuffer)) == NULL) {
        hijack_shutdown(hh);
        hh = NULL;
    } else if ((hh->sock = network_raw_sock_open(hh->errorBuffer)) == -1) {
        hijack_shutdown(hh);
        hh = NULL;
    }

    return hh;
}

void hijack_shutdown(hijack_t * hh) {
    if (hh) {
        if (hh->pd) {
            pcap_close(hh->pd);
            hh->pd = NULL;
        }
        if (hh->sock != -1) {
            close(hh->sock);
            hh->sock = -1;
        }
        free(hh);
    }
}

char * hijack_error(hijack_t * hh) {
    return hh->errorBuffer;
}

int hijack(hijack_t * hh) {
    int ret;

    if (!target_is_vulnerable(hh)) {
        fprintf(stderr, "[!] Target appears as not vulnerable, abort!\n");
        ret = 1;
    } else if (!get_client_port(hh)) {
        fprintf(stderr, "[!] Cannot find the client's port number, abort!\n");
        ret = 2;
    } else if (!get_server_snd_next(hh)) {
        fprintf(stderr, "[!] Cannot find the server's SND_NEXT, abort!\n");
        ret = 3;
    } else if (!get_client_snd_next(hh)) {
        fprintf(stderr, "[!] Cannot find the client's SND_NEXT, abort!\n");
        ret = 4;
    } else {
        /* 
         * Once all information required correctly gathered
         * we can now inject our traffic in the connection
         */
        fprintf(stdout, "[+] Informations gathered, perform traffic injection...\n");
        if (!inject_content(hh)) {
            fprintf(stdout, "[+] Injection performed!\n");
            ret = 0;
        } else {
            fprintf(stderr, "[!] Injection failed!\n");
            ret = 5;
        }
    }
    return ret;
}


/*
 * -- --- -- --- INTERNAL STUFF --- -- --- --
 */

/*
 * The method used to check if the target is
 * vulnerable or not is the following :
 *      - send one probe
 *      - wait a few seconds
 *      - resend a probe
 *      [...until we have enough information...]
 *      - compare returned IP ID and check for linearity
 */
static bool target_is_vulnerable(hijack_t * hh) {
    int returnedIpId[MAX_VULN_CHECK_PROBES] = {0x00};
    int idle = VULN_CHECK_IDLE_SECONDS, i;
    reply_t reply;
    uint32_t timeout = 200;     /* in msecs */
    struct timeval now, oldnow; /* check if our test has timed out */
    char filter[256];
    
    /* apply a pcap filter */
    snprintf(filter, sizeof(filter), "icmp and ip src %s", inet_ntoa(o.clientNetAddr));
    set_pcap_filter(hh->pd, filter);


    /* 
     * probing loop
     */
    gettimeofday(&now, NULL);
    for (i=0; i<MAX_VULN_CHECK_PROBES; i++) {
        network_send_icmp_echo(hh->sock, o.clientNetAddr);
        while(timeout>0 && !receive_reply(hh->pd, &reply, timeout)) {
            oldnow = now;
            returnedIpId[i] = get_ip_id(&reply);
            if (returnedIpId[i] < 0) {
                /* not a valid ip packet */
                continue;
            }
            timeout -= TIMEVAL_DIFF(now, oldnow);
        }
#if defined(DEBUG)
        printf("Returned IP id #%d : %d\n", i, returnedIpId[i]);
#endif
        sleep(idle);
    }

    /*
     * checking loop
     */
    for (i=1; i<MAX_VULN_CHECK_PROBES; i++) {
        /* just check for increasing IP ids */
        if (returnedIpId[i-1] > returnedIpId[i]) {
            return false;
        }
    }

    return true;
}

static bool get_client_port(hijack_t * hh) {
    sprintf(hh->errorBuffer, "Function not implemented");
    return false;
}

static bool get_server_snd_next(hijack_t * hh) {
    sprintf(hh->errorBuffer, "Function not implemented");
    return false;
}

static bool get_client_snd_next(hijack_t * hh) {
    sprintf(hh->errorBuffer, "Function not implemented");
    return false;
}

static uint32_t inject_content(hijack_t * hh) {
    sprintf(hh->errorBuffer, "Function not implemented");
    return 0;
}

